using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//Encoding：UTF-8
public class PaiJuManager : MonoBehaviour
{
    public static PaiJuManager singleton;

    [Tooltip("有无风牌")] public bool haveFeng = true;
    [Tooltip("有无红中牌")] public bool haveZhong = true;
    [Tooltip("有无发财牌")] public bool haveFa = true;
    [Tooltip("有无白板牌")] public bool haveBai = true;
    [Tooltip("是否允许吃牌")] public bool canChi = true;
    [Tooltip("是否必须听牌")] public bool mustTing = true;
    private List<int> paiDui;
    private int paiDuiTopIndex; // 牌堆顶序号
    private int gangTouIndex; // 杠头序号
    private List<IPlayer> players = new List<IPlayer>();
    private int activedPlayerIndex; // 正在进行活动的玩家序号
    private int ActivedPlayerIndex { get { return activedPlayerIndex; } set { if (value > 3) activedPlayerIndex = 0; else if (value < 0) activedPlayerIndex = 3; else activedPlayerIndex = value; } }
    private int turnCount;

    private readonly int _MAJIANGMAXCOUNT = 136;

    PaiJuManager()
    {
        singleton = this;
    }

    public IPlayer GetPlayerController()
    {
        return players[0];
    }

    public void Play()
    {
        NewPlayer();
        ResetPaiDui();
        Shuffle();
        InitHand();
    }

    private void NewPlayer()
    {
        //新建玩家
        players.Clear();
        players.Add(new PlayerController(0));
        players.Add(new RobotController(1));
        players.Add(new RobotController(2));
        players.Add(new RobotController(3));
    }

    private void ResetPaiDui()
    {
        //根据设置初始化牌堆
        paiDui = new List<int>();
        gangTouIndex = 0;
        int maJiangCount = _MAJIANGMAXCOUNT;
        if (haveFeng)
        {
            AddPaiDui(4);
            AddPaiDui(5);
            AddPaiDui(6);
            AddPaiDui(7);
        }
        else
        {
            maJiangCount -= 16;
        }
        if (haveZhong) AddPaiDui(1); else maJiangCount -= 4;
        if (haveFa) AddPaiDui(2); else maJiangCount -= 4;
        if (haveBai) AddPaiDui(3); else maJiangCount -= 4;
        paiDuiTopIndex = maJiangCount - 1;
        AddPaiDui(11);
        AddPaiDui(12);
        AddPaiDui(13);
        AddPaiDui(14);
        AddPaiDui(15);
        AddPaiDui(16);
        AddPaiDui(17);
        AddPaiDui(18);
        AddPaiDui(19);
        AddPaiDui(21);
        AddPaiDui(22);
        AddPaiDui(23);
        AddPaiDui(24);
        AddPaiDui(25);
        AddPaiDui(26);
        AddPaiDui(27);
        AddPaiDui(28);
        AddPaiDui(29);
        AddPaiDui(31);
        AddPaiDui(32);
        AddPaiDui(33);
        AddPaiDui(34);
        AddPaiDui(35);
        AddPaiDui(36);
        AddPaiDui(37);
        AddPaiDui(38);
        AddPaiDui(39);
    }

    private void AddPaiDui(int id)
    {
        for (int i = 0; i < 4; ++i)
        {
            paiDui.Add(id);
        }
    }

    private void Shuffle()
    {
        //洗牌 Knuth-Durstenfeld Shuffle
        for (int i = paiDui.Count - 1; i > 1; --i)
        {
            int k = Random.Range(0, i - 1);
            int id = paiDui[k];
            paiDui[k] = paiDui[i];
            paiDui[i] = id;
        }
    }

    private void InitHand()
    {
        //发初始手牌
        for (int i = 0; i < players.Count; ++i)
        {
            int[] paiIDs = new int[13];
            for (int j = 0; j < 13; ++j)
            {
                paiIDs[j] = paiDui[paiDuiTopIndex];
                --paiDuiTopIndex;
            }
            players[i].DrawOnStart(paiIDs);
        }
        StartCoroutine(Turn());
    }

    private int GetNextPai()
    {
        --paiDuiTopIndex;
        return paiDui[paiDuiTopIndex + 1];
    }

    private int GetGangTou()
    {
        ++gangTouIndex;
        return paiDui[gangTouIndex - 1];
    }

    IEnumerator Turn()
    {
        turnCount = 0;
        ActivedPlayerIndex = -1;
        while (true)
        {
            ++turnCount;
            bool needDrawNextPai = true;

            // 非首轮庄家需要判断其余三家是否可以碰、杠
            if (turnCount != 1)
            {
                for (int i = 0; i < players.Count; ++i)
                {
                    if (i != ActivedPlayerIndex && players[i].CanPeng())
                    {
                        IPlayer pTemp1 = players[i];
                        bool isGang = pTemp1.CanGang();
                        pTemp1.AllowAction(playPai: false, chi: false, peng: true, gang: isGang, anGang: false, jiaGang: false, ting: false, hu: false, ziMo: false, skip: true);
                        yield return new WaitUntil(() => pTemp1.EqualsAction(PlayerBase.Action.Peng) || pTemp1.EqualsAction(PlayerBase.Action.Gang) || pTemp1.EqualsAction(PlayerBase.Action.Skip));
                        if (pTemp1.EqualsAction(PlayerBase.Action.Peng))
                        {
                            pTemp1.Peng();
                            ActivedPlayerIndex = i;
                            needDrawNextPai = false;
                        }
                        else if (pTemp1.EqualsAction(PlayerBase.Action.Gang))
                        {
                            pTemp1.Gang();
                            pTemp1.Draw(GetGangTou());
                            ActivedPlayerIndex = i;
                            needDrawNextPai = false;

                            // 判断是否自摸（杠上开花）
                            if (pTemp1.CanZiMo())
                            {
                                pTemp1.AllowAction(playPai: false, chi: false, peng: false, gang: false, anGang: false, jiaGang: false, ting: false, hu: false, ziMo: true, skip: true);
                                yield return new WaitUntil(() => pTemp1.EqualsAction(PlayerBase.Action.ZiMo) || pTemp1.EqualsAction(PlayerBase.Action.Skip));
                                if (pTemp1.EqualsAction(PlayerBase.Action.ZiMo))
                                {
                                    UIGameMenu.singleton.GameOver();
                                    yield break;
                                }
                            }
                        }
                        break;
                    }
                }
            }

            // 摸牌阶段
            if (needDrawNextPai)
            {
                // 正常转到下家
                ++ActivedPlayerIndex;
                IPlayer pTemp2 = players[ActivedPlayerIndex];
                pTemp2.Draw(GetNextPai());

                // 判断是否自摸
                if (pTemp2.CanZiMo())
                {
                    pTemp2.AllowAction(playPai: false, chi: false, peng: false, gang: false, anGang: false, jiaGang: false, ting: false, hu: false, ziMo: true, skip: true);
                    yield return new WaitUntil(() => pTemp2.EqualsAction(PlayerBase.Action.ZiMo) || pTemp2.EqualsAction(PlayerBase.Action.Skip));
                    if (pTemp2.EqualsAction(PlayerBase.Action.ZiMo))
                    {
                        UIGameMenu.singleton.GameOver();
                        yield break;
                    }
                }
            }

            // 出牌阶段之前检查手牌是否有暗杠和加杠
            bool isCheckGang = true;
            while (isCheckGang)
            {
                isCheckGang = false;
                if (paiDuiTopIndex < gangTouIndex) // 摸最后一张牌后不能暗杠和加杠
                    break;
                else
                {
                    IPlayer pTemp2 = players[ActivedPlayerIndex];

                    // 判断是否暗杠
                    if (pTemp2.CanAnGang())
                    {
                        pTemp2.AllowAction(playPai: false, chi: false, peng: false, gang: false, anGang: true, jiaGang: false, ting: false, hu: false, ziMo: false, skip: true);
                        yield return new WaitUntil(() => pTemp2.EqualsAction(PlayerBase.Action.AnGang) || pTemp2.EqualsAction(PlayerBase.Action.Skip));
                        if (pTemp2.EqualsAction(PlayerBase.Action.AnGang))
                        {
                            pTemp2.AnGang();
                            pTemp2.Draw(GetGangTou());
                            isCheckGang = true;
                        }
                    }

                    // 判断是否加杠
                    if (pTemp2.CanJiaGang())
                    {
                        pTemp2.AllowAction(playPai: false, chi: false, peng: false, gang: false, anGang: false, jiaGang: true, ting: false, hu: false, ziMo: false, skip: true);
                        yield return new WaitUntil(() => pTemp2.EqualsAction(PlayerBase.Action.JiaGang) || pTemp2.EqualsAction(PlayerBase.Action.Skip));
                        if (pTemp2.EqualsAction(PlayerBase.Action.JiaGang))
                        {
                            pTemp2.JiaGang();
                            pTemp2.Draw(GetGangTou());
                            isCheckGang = true;
                        }
                    }

                    // 判断是否自摸（杠上开花）
                    if (isCheckGang && pTemp2.CanZiMo())
                    {
                        pTemp2.AllowAction(playPai: false, chi: false, peng: false, gang: false, anGang: false, jiaGang: false, ting: false, hu: false, ziMo: true, skip: true);
                        yield return new WaitUntil(() => pTemp2.EqualsAction(PlayerBase.Action.ZiMo) || pTemp2.EqualsAction(PlayerBase.Action.Skip));
                        if (pTemp2.EqualsAction(PlayerBase.Action.ZiMo))
                        {
                            UIGameMenu.singleton.GameOver();
                            yield break;
                        }
                    }
                }
            }

            // 出牌阶段
            while (true)
            {
                IPlayer pTemp3 = players[ActivedPlayerIndex];
                pTemp3.AllowAction(playPai: true, chi: false, peng: false, gang: false, anGang: false, jiaGang: false, ting: false, hu: false, ziMo: false, skip: false);
                yield return new WaitUntil(() => pTemp3.EqualsAction(PlayerBase.Action.PlayPai));
                if (pTemp3.PlayPai())
                {
                    break;
                }
            }

            // 判断其他三家是否可以胡
            for (int i = 0; i < players.Count; ++i)
            {
                if (i != ActivedPlayerIndex && players[i].CanHu())
                {
                    IPlayer pTemp4 = players[i];
                    pTemp4.AllowAction(playPai: false, chi: false, peng: false, gang: false, anGang: false, jiaGang: false, ting: false, hu: true, ziMo: false, skip: true);
                    yield return new WaitUntil(() => pTemp4.EqualsAction(PlayerBase.Action.Hu) || pTemp4.EqualsAction(PlayerBase.Action.Skip));
                    if (pTemp4.EqualsAction(PlayerBase.Action.Hu))
                    {
                        UIGameMenu.singleton.GameOver();
                        yield break;
                    }
                }
            }

            // 判断是否流局
            if (paiDuiTopIndex < gangTouIndex)
            {
                UIGameMenu.singleton.GameOver();
                yield break;
            }

            // 判断本家是否可以听
        }
    }
}
